/* 
 * Copyright (C) 2001-2003 Jacek Sieka, j_s@telia.com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#if !defined(AFX_SEARCHFRM_H__A7078724_FD85_4F39_8463_5A08A5F45E33__INCLUDED_)
#define AFX_SEARCHFRM_H__A7078724_FD85_4F39_8463_5A08A5F45E33__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

#include "FlatTabCtrl.h"
#include "TypedListViewCtrl.h"
#include "WinUtil.h"

#include "../client/Client.h"
#include "../client/SearchManager.h"
#include "../client/CriticalSection.h"
#include "../client/ClientManagerListener.h"

#include "UCHandler.h"

#define SEARCH_MESSAGE_MAP 6		// This could be any number, really...
#define SHOWUI_MESSAGE_MAP 7

class SearchFrame : public MDITabChildWindowImpl<SearchFrame, RGB(127, 127, 255)>, 
	private SearchManagerListener, private ClientManagerListener, 
	public UCHandler<SearchFrame>, public UserInfoBaseHandler<SearchFrame>
	// CDM EXTENSION BEGINS
	,public CSplitterImpl<SearchFrame, false>
	// CDM EXTENSION ENDS
{
public:
	static void openWindow(const string& str = Util::emptyString, LONGLONG size = 0, SearchManager::SizeModes mode = SearchManager::SIZE_ATLEAST, SearchManager::TypeModes type = SearchManager::TYPE_ANY);

	DECLARE_FRAME_WND_CLASS_EX(_T("SearchFrame"), IDR_SEARCH, 0, COLOR_3DFACE)

	typedef MDITabChildWindowImpl<SearchFrame, RGB(127, 127, 255)> baseClass;
	typedef UCHandler<SearchFrame> ucBase;
	typedef UserInfoBaseHandler<SearchFrame> uicBase;
	// CDM EXTENSION BEGINS
	typedef CSplitterImpl<SearchFrame, false> splitBase;
	// CDM EXTENSION ENDS

	BEGIN_MSG_MAP(SearchFrame)
		NOTIFY_HANDLER(IDC_RESULTS, LVN_GETDISPINFO, ctrlResults.onGetDispInfo)
		NOTIFY_HANDLER(IDC_RESULTS, LVN_COLUMNCLICK, ctrlResults.onColumnClick)
		NOTIFY_HANDLER(IDC_HUB, LVN_GETDISPINFO, ctrlHubs.onGetDispInfo)
		NOTIFY_HANDLER(IDC_RESULTS, NM_DBLCLK, onDoubleClickResults)
		NOTIFY_HANDLER(IDC_RESULTS, LVN_KEYDOWN, onKeyDown)
		NOTIFY_HANDLER(IDC_HUB, LVN_ITEMCHANGED, onItemChangedHub)
		// pothead extension starts (r2 code) #7
		NOTIFY_HANDLER(IDC_RESULTS, NM_CLICK, onLButton)
		// pothead extension ends (r2 code)
		// CDM EXTENSION BEGINS
		NOTIFY_HANDLER(IDC_UNRESPONDED, LVN_GETDISPINFO, ctrlUnresponded.onGetDispInfo)
		NOTIFY_HANDLER(IDC_UNRESPONDED, LVN_COLUMNCLICK, ctrlUnresponded.onColumnClick)
		NOTIFY_HANDLER(IDC_HUB, NM_RCLICK, onRightClickHub)
		NOTIFY_HANDLER(IDC_RESULTS, NM_CUSTOMDRAW, onCustomDraw)
		COMMAND_ID_HANDLER(IDC_SHOW_UNRESPONDED, onShowUnresponded)
		COMMAND_ID_HANDLER(IDC_COPY_UNRESPONDED_NICK, onCopyUnrespondedNick)
		COMMAND_ID_HANDLER(IDC_REMOVE_UNRESPONDED, onRemoveUnresponded)
		COMMAND_ID_HANDLER(IDC_GETLIST_UNRESPONDED, onGetListUnresponded)
		// CDM EXTENSION ENDS
		MESSAGE_HANDLER(WM_CREATE, onCreate)
		MESSAGE_HANDLER(WM_SETFOCUS, onFocus)
		MESSAGE_HANDLER(WM_CONTEXTMENU, onContextMenu)
		MESSAGE_HANDLER(WM_SPEAKER, onSpeaker)
		MESSAGE_HANDLER(WM_CTLCOLOREDIT, onCtlColor)
		MESSAGE_HANDLER(WM_CTLCOLORSTATIC, onCtlColor)
		MESSAGE_HANDLER(WM_CTLCOLORLISTBOX, onCtlColor)
		MESSAGE_HANDLER(WM_CLOSE, onClose)
		COMMAND_ID_HANDLER(IDC_DOWNLOAD, onDownload)
		COMMAND_ID_HANDLER(IDC_DOWNLOADTO, onDownloadTo)
		COMMAND_ID_HANDLER(IDC_DOWNLOADDIR, onDownloadWhole)
		COMMAND_ID_HANDLER(IDC_DOWNLOADDIRTO, onDownloadWholeTo)
		COMMAND_ID_HANDLER(IDC_VIEW_AS_TEXT, onViewAsText)
		COMMAND_ID_HANDLER(IDC_REMOVE, onRemove)
		COMMAND_ID_HANDLER(IDC_SEARCH, onSearch)
		COMMAND_ID_HANDLER(IDC_FREESLOTS, onFreeSlots)
		COMMAND_ID_HANDLER(IDC_GETLIST, onGetList)
		// potheads extension starts (R2 Code) #7
		COMMAND_ID_HANDLER(IDC_SEARCH_BY_TTH, onSearchByTTH)
		// potheads extension ends (R2 Code)
		// R2 extension begins svn126
		COMMAND_ID_HANDLER(IDC_COPY_LINK, onCopyMagnetLink)		
		// R2 extension ends svn126
		COMMAND_RANGE_HANDLER(IDC_DOWNLOAD_TARGET, IDC_DOWNLOAD_TARGET + targets.size() + WinUtil::lastDirs.size(), onDownloadTarget)
		COMMAND_RANGE_HANDLER(IDC_DOWNLOAD_WHOLE_TARGET, IDC_DOWNLOAD_WHOLE_TARGET + WinUtil::lastDirs.size(), onDownloadWholeTarget)
		// CDM EXTENSION BEGINS
		COMMAND_RANGE_HANDLER(IDC_MULTI_COPY, IDC_MULTI_COPY + SearchFrame::COLUMN_LAST - 1, onMultiCopy)
		CHAIN_MSG_MAP(splitBase)
		// CDM EXTENSION ENDS
		CHAIN_COMMANDS(ucBase)
		CHAIN_COMMANDS(uicBase)
		CHAIN_MSG_MAP(baseClass)
		// potheads extension starts (R2 Code) #7
		REFLECT_NOTIFICATIONS()
		// potheads extension ends (R2 Code)
	ALT_MSG_MAP(SEARCH_MESSAGE_MAP)
		MESSAGE_HANDLER(WM_CHAR, onChar)
		MESSAGE_HANDLER(WM_KEYDOWN, onChar)
		MESSAGE_HANDLER(WM_KEYUP, onChar)
		MESSAGE_HANDLER(WM_CTLCOLORLISTBOX, onCtlColor)
		MESSAGE_HANDLER(WM_CTLCOLOREDIT, onCtlColor)
	ALT_MSG_MAP(SHOWUI_MESSAGE_MAP)
		MESSAGE_HANDLER(BM_SETCHECK, onShowUI)
	END_MSG_MAP()

	SearchFrame() : 
	searchBoxContainer(_T("COMBOBOX"), this, SEARCH_MESSAGE_MAP),
		searchContainer(_T("edit"), this, SEARCH_MESSAGE_MAP), 
		sizeContainer(_T("edit"), this, SEARCH_MESSAGE_MAP), 
		modeContainer(_T("COMBOBOX"), this, SEARCH_MESSAGE_MAP),
		sizeModeContainer(_T("COMBOBOX"), this, SEARCH_MESSAGE_MAP),
		fileTypeContainer(_T("ComboBoxEx32"), this, SEARCH_MESSAGE_MAP),
		fileTypeSubContainer(_T("COMBOBOX"), this, SEARCH_MESSAGE_MAP),
		showUIContainer(_T("BUTTON"), this, SHOWUI_MESSAGE_MAP),
		slotsContainer(_T("BUTTON"), this, SEARCH_MESSAGE_MAP),
		doSearchContainer(_T("BUTTON"), this, SEARCH_MESSAGE_MAP),
		resultsContainer(WC_LISTVIEW, this, SEARCH_MESSAGE_MAP),
		// CDM EXTENSION BEGINS
		unrespondedContainer(WC_LISTVIEW, this, SEARCH_MESSAGE_MAP),
		showUnrespondedContainer(_T("BUTTON"), this, SEARCH_MESSAGE_MAP),
		// CDM EXTENSION ENDS
		// potheads extension starts (R2 Code) #7
		searchInProgress(false),
		tthContainer(_T("BUTTON"), this, SEARCH_MESSAGE_MAP),
		// potheads extension ends (R2 Code)
		hubsContainer(WC_LISTVIEW, this, SEARCH_MESSAGE_MAP),
		lastSearch(0), initialSize(0), initialMode(SearchManager::SIZE_ATLEAST), initialType(SearchManager::TYPE_ANY),
		showUI(true), onlyFree(false), closed(false), isHash(false)
		// potheads extension starts (R2 Code) #7
		,exactSize(false)
		// potheads extension ends (R2 Code)
	{	
		SearchManager::getInstance()->addListener(this);
	}

	virtual ~SearchFrame() {
		// potheads extension starts (R2 Code) #7
		states.Destroy();
		// potheads extension ends (R2 Code)
	}
	virtual void OnFinalMessage(HWND /*hWnd*/) { delete this; }

	LRESULT onChar(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled);
	LRESULT onClose(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
	LRESULT onContextMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled);
	LRESULT onCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled);
	LRESULT onCtlColor(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/);
	LRESULT onDoubleClickResults(int idCtrl, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/);
	LRESULT onDownloadTarget(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	LRESULT onDownloadTo(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	LRESULT onDownloadWholeTarget(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	LRESULT onDownloadWholeTo(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	LRESULT onSpeaker(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/);
	// CDM EXTENSION BEGINS
	LRESULT onMultiCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	LRESULT onCustomDraw(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled);
	LRESULT onShowUnresponded(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	LRESULT onCopyUnrespondedNick(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	LRESULT onRemoveUnresponded(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		removeSelectedUnresponded();
		return 0;
	};
	LRESULT onGetListUnresponded(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
	void removeSelectedUnresponded();
	// CDM EXTENSION ENDS
	// potheads extension starts (R2 Code) #7
	LRESULT onSearchByTTH(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
// R2 extesnion begins svn126
	LRESULT onCopyMagnetLink(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
// R2 extension ends svn126
	LRESULT onLButton(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled); 
	// potheads extension ends (R2 Code)
	void UpdateLayout(BOOL bResizeBars = TRUE);
	void runUserCommand(UserCommand& uc);

	void removeSelected() {
		int i = -1;
		while( (i = ctrlResults.GetNextItem(-1, LVNI_SELECTED)) != -1) {
			// potheads extension starts (R2 Code) #7
			SearchInfo* s = (SearchInfo*)ctrlResults.getItemData(i);
			if(s->subItems.size() > 0) {
				int q = 0;
				while(q < static_cast<int>(s->subItems.size())) {
					SearchInfo* j = s->subItems[q];
					int k = ctrlResults.findItem(j);
					delete j;
					ctrlResults.DeleteItem(k);
					q++;
				}
				s->subItems.clear();
			}
			
			if(s->main != NULL) {
				SearchInfo::List::iterator n = find(s->main->subItems.begin(), s->main->subItems.end(), s);
				if(n != s->main->subItems.end()) s->main->subItems.erase(n);
				if(s->main->subItems.size() == 0) {
					s->main->setHits("");
					ctrlResults.SetItemState(ctrlResults.findItem(s->main), INDEXTOSTATEIMAGEMASK(0), LVIS_STATEIMAGEMASK);
				} else {
					s->main->setHits(Util::toString((int)s->main->subItems.size() + 1)+" "+STRING(HUB_USERS));
					// potheads extension ends (R2 Code)
					delete ctrlResults.getItemData(i);
					ctrlResults.DeleteItem(i);
				}
			}
	
	// potheads extension starts (R2 Code) #7
			SearchInfo::List::iterator k = find(mainItems.begin(), mainItems.end(), s);
			if(k != mainItems.end()) mainItems.erase(k);
			int l = ctrlResults.findItem(s);
			delete s;
			ctrlResults.DeleteItem(l);
		}
		ctrlResults.resort();
	}
	// potheads extension ends (R2 Code)

	LRESULT onDownload(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		ctrlResults.forEachSelectedT(SearchInfo::Download(SETTING(DOWNLOAD_DIRECTORY)));
		return 0;
	}

	LRESULT onViewAsText(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		ctrlResults.forEachSelected(&SearchInfo::view);
		return 0;
	}

	LRESULT onGetList(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);

	LRESULT onDownloadWhole(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		ctrlResults.forEachSelectedT(SearchInfo::DownloadWhole(SETTING(DOWNLOAD_DIRECTORY)));
		return 0;
	}
	
	LRESULT onRemove(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		removeSelected();
		return 0;
	}

	LRESULT onFreeSlots(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		onlyFree = (ctrlSlots.GetCheck() == 1);
		return 0;
	}

	LRESULT onSearch(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
		// potheads extension starts (R2 Code) #7
		if(searchInProgress == true) {
			stopSearch();
	 	} else {
			onEnter();
		}
		// potheads extension ends (R2 Code)
		return 0;
	}

	// potheads extension starts (R2 Code) #7
	void startSearch() {
		searchInProgress = true;
		ctrlDoSearch.SetWindowText(CTSTRING(STOP_SEARCH));
	}

	void stopSearch() {
		search.clear();
		searchInProgress = false;
		ctrlDoSearch.SetWindowText(CTSTRING(SEARCH));
		ctrlStatus.SetText(1, CTSTRING(SEARCH_STOPPED));
	}
	// potheads extension ends (R2 Code)

	LRESULT onKeyDown(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/) {
		NMLVKEYDOWN* kd = (NMLVKEYDOWN*) pnmh;
		
		if(kd->wVKey == VK_DELETE) {
			removeSelected();
		} 
		return 0;
	}

	LRESULT onFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) {
		if(::IsWindow(ctrlSearch))
			ctrlSearch.SetFocus();
		return 0;
	}

	LRESULT onShowUI(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) {
		bHandled = FALSE;
		showUI = (wParam == BST_CHECKED);
		UpdateLayout(FALSE);
		return 0;
	}

	void SearchFrame::setInitial(const string& str, LONGLONG size, SearchManager::SizeModes mode, SearchManager::TypeModes type) {
		initialString = str; initialSize = size; initialMode = mode; initialType = type;
	}
	
private:
	class SearchInfo;
	// CDM EXTENSION BEGINS
	class UnrespondedInfo;
	// CDM EXTENSION ENDS
	// potheads extension starts (R2 Code) #7
	bool searchInProgress;
	int maxResults;
	// potheads extension ends (R2 Code)
public:
	TypedListViewCtrl<SearchInfo, IDC_RESULTS>& getUserList() { return ctrlResults; };

private:
	enum {
		COLUMN_FIRST,
		COLUMN_FILENAME = COLUMN_FIRST,
		// potheads extension starts (R2 Code) #7
		COLUMN_HITS,
		// potheads extension ends (R2 Code)
		COLUMN_NICK,
		COLUMN_TYPE,
		COLUMN_SIZE,
		COLUMN_PATH,
		COLUMN_SLOTS,
		// CDM EXTENSION BEGINS
		COLUMN_TAG_SLOTS,
		// CDM EXTENSION ENDS
		COLUMN_CONNECTION,
		COLUMN_HUB,
		COLUMN_EXACT_SIZE,
		COLUMN_IP,
		COLUMN_TTH,
		COLUMN_LAST
	};
	// CDM EXTENSION BEGINS
	class UnrespondedInfo : public UserInfoBase {
	public:
		UnrespondedInfo(const User::Ptr& u) : UserInfoBase(u), nick(u->getNick()), op(false) { };

		const string& getText(int /*col*/) const {
			return user->getNick();
		}
		static int compareItems(UnrespondedInfo* a, UnrespondedInfo* b, int/* col*/) {
			return Util::stricmp(a->user->getNick(), b->user->getNick());
		}
		GETSET(string, nick, Nick);
		GETSET(string, hub, Hub);
		GETSET(bool, op, Op);

		void getList();
		//Sulan start svn101
		int imageIndex() { 
			return WinUtil::getIconIndex(""); //@Fixme
		}
		//End
	};
	// CDM EXTENSION ENDS
	class SearchInfo : public UserInfoBase {
	public:
		SearchResult* sr;
		// potheads extension starts (R2 Code) #7
		typedef SearchInfo* Ptr;
		typedef vector<Ptr> List;
		typedef List::iterator Iter;

		SearchInfo::List subItems;
		//SearchInfo(SearchResult* aSR) : UserInfoBase(aSR->getUser()), sr(aSR) { 
		SearchInfo(SearchResult* aSR) : UserInfoBase(aSR->getUser()), sr(aSR), collapsed(true), mainitem(false), main(NULL) { 
		// potheads extension ends (R2 Code)
			sr->incRef(); update();
		};
		~SearchInfo() { 
			sr->decRef(); 
		};
		// potheads extension starts (R2 Code) #7
		bool collapsed;
		bool mainitem;
		SearchInfo* main;
		// potheads extension ends (R2 Code)
		void getList();
		void view();
		struct Download {
			Download(const string& aTarget) : tgt(aTarget) { };
			void operator()(SearchInfo* si);
			const string& tgt;
		};
		struct DownloadWhole {
			DownloadWhole(const string& aTarget) : tgt(aTarget) { };
			void operator()(SearchInfo* si);
			const string& tgt;
		};
		struct DownloadTarget {
			DownloadTarget(const string& aTarget) : tgt(aTarget) { };
			void operator()(SearchInfo* si);
			const string& tgt;
		};
		struct CheckSize {
			// potheads extension starts (R2 Code) #7
			//CheckSize() : size(-1), op(true), oneHub(true) { };
			CheckSize() : size(-1), op(true), oneHub(true), hasTTH(false) { };
			bool hasTTH;
			string tth;
			// potheads extension ends (R2 Code)
			void operator()(SearchInfo* si);
			string ext;
			int64_t size;
			bool oneHub;
			string hub;
			bool op;
		};

		const string& getText(int col) const {
			switch(col) {
				case COLUMN_NICK: return sr->getUser()->getNick();
				case COLUMN_FILENAME: return fileName;
				case COLUMN_TYPE: return type;
				case COLUMN_SIZE: return size;
				case COLUMN_PATH: return path;
				case COLUMN_SLOTS: return slots;
				// CDM EXTENSION BEGINS
				case COLUMN_TAG_SLOTS: return sr->getUser()->getTagSlots();
				// CDM EXTENSION ENDS
				case COLUMN_CONNECTION: return sr->getUser()->getConnection();
				case COLUMN_HUB: return sr->getHubName();
				case COLUMN_EXACT_SIZE: return exactSize;
				case COLUMN_IP: return ip;
				// potheads extension starts (R2 Code) #7
				//case COLUMN_TTH: return tth;
				case COLUMN_TTH: return getTTH();
				case COLUMN_HITS: return hits;
				// potheads extension ends (R2 Code)
				default: return Util::emptyString;
			}
		}

		static int compareItems(SearchInfo* a, SearchInfo* b, int col) {
			// potheads extension starts (R2 Code) #7
				//case COLUMN_TTH: return tth;
			bool canBeSorted = false;
			if (a->mainitem && b->mainitem)
				if(a->collapsed && b->collapsed)
					canBeSorted = true;
			if(a->sr->getTTH() && b->sr->getTTH())
				if (*a->sr->getTTH() == *b->sr->getTTH())
					if((!a->mainitem) && (!b->mainitem))
						canBeSorted = true;

			if(canBeSorted){
				// potheads extension ends (R2 Code)
				switch(col) {
					case COLUMN_NICK: return Util::stricmp(a->sr->getUser()->getNick(), b->sr->getUser()->getNick());
					case COLUMN_FILENAME: return Util::stricmp(a->fileName, b->fileName);
					case COLUMN_TYPE: 
						if(a->sr->getType() == b->sr->getType())
							return Util::stricmp(a->type, b->type);
						else
							return(a->sr->getType() == SearchResult::TYPE_DIRECTORY) ? -1 : 1;
					case COLUMN_SIZE: return compare(a->sr->getSize(), b->sr->getSize());
					// potheads extension starts (R2 Code) #7
					case COLUMN_HITS: return compare(a->subItems.size(), b->subItems.size());
					// potheads extension ends (R2 Code)
					case COLUMN_PATH: return Util::stricmp(a->path, b->path);
					case COLUMN_SLOTS: 
						if(a->sr->getFreeSlots() == b->sr->getFreeSlots())
							return compare(a->sr->getSlots(), b->sr->getSlots());
						else
							return compare(a->sr->getFreeSlots(), b->sr->getFreeSlots());
					// CDM EXTENSION BEGINS
						case COLUMN_TAG_SLOTS: 
						{
							string tsa = a->sr->getUser()->getTagSlots();
							string tsb = b->sr->getUser()->getTagSlots();
							if(Util::isNumeric(tsa) && Util::isNumeric(tsb)) {
								return compare(Util::toInt(tsa), Util::toInt(tsb));
							}
							return Util::stricmp(tsa, tsb);
						}
					// CDM EXTENSION ENDS
					case COLUMN_CONNECTION: return Util::stricmp(a->sr->getUser()->getConnection(), b->sr->getUser()->getConnection());
					case COLUMN_HUB: return Util::stricmp(a->sr->getHubName(), b->sr->getHubName());
					case COLUMN_EXACT_SIZE: return compare(a->sr->getSize(), b->sr->getSize());
					case COLUMN_IP: return Util::stricmp(a->getIP(), b->getIP());
					case COLUMN_TTH: return Util::stricmp(a->getTTH(), b->getTTH());
					default: return 0;
				}
			// potheads extension starts (R2 Code) #7
			} else return 0;
			// potheads extension ends (R2 Code)
		}

		void update() { 
			if(sr->getType() == SearchResult::TYPE_FILE) {
				if(sr->getFile().rfind('\\') == string::npos) {
					fileName = sr->getFile();
				} else {
					fileName = Util::getFileName(sr->getFile());
					path = Util::getFilePath(sr->getFile());
				}

				type = Util::getFileExt(fileName);
				if(!type.empty() && type[0] == '.')
					type.erase(0, 1);
				size = Util::formatBytes(sr->getSize());
				// potheads extension starts (R2 Code) #7
				//exactSize = Util::formatNumber(sr->getSize());
				exactSize = Util::formatExactSize(sr->getSize());
				// potheads extension ends (R2 Code)
				exactSize = Util::formatNumber(sr->getSize());
			} else {
				fileName = sr->getFileName();
				path = sr->getFile();
				type = STRING(DIRECTORY);
			}
			slots = sr->getSlotString();
			ip = sr->getIP();
			if(sr->getTTH() != NULL)
				setTTH(sr->getTTH()->toBase32());
			// CDM EXTENSION BEGINS
			if( !(sr->getUser()->getTagSlots().empty()) ) {
				slotMismatch = ( Util::toString(sr->getSlots()).compare(sr->getUser()->getTagSlots()) != 0 );
			} else {
				slotMismatch = false;
			}
			// CDM EXTENSION ENDS
		}

		GETSET(string, fileName, FileName);
		GETSET(string, path, Path);
		GETSET(string, type, Type);
		GETSET(string, size, Size);
		GETSET(string, slots, Slots);
		GETSET(string, exactSize, ExactSize);
		GETSET(string, ip, IP);
		GETSET(string, tth, TTH);
		// CDM EXTENSION BEGINS
		GETSET(bool, slotMismatch, SlotMismatch);
		// CDM EXTENSION ENDS
		// potheads extension starts (R2 Code) #7
		GETSET(string, hits, Hits);
		// potheads extension ends (R2 Code)
		//Sulan start svn101
		int imageIndex() { 
			return WinUtil::getIconIndex(fileName);
		}
		//End
	};

	struct HubInfo : public FastAlloc<HubInfo> {
		HubInfo(const string& aIpPort, const string& aName, bool aOp, bool aDis) : ipPort(aIpPort),
			name(aName), op(aOp), disableDefaultSearch(aDis) { };

		const string& getText(int col) const {
		// potheads extension starts (R2 Code) #7
		//return name;
			return (col == 0) ? name : Util::emptyString;
		// potheads extension ends (R2 Code)
		}
		static int compareItems(HubInfo* a, HubInfo* b, int col) {
		// potheads extension starts (R2 Code) #7
			return (col == 0) ? Util::stricmp(a->name, b->name) : 0;
			// potheads extension ends (R2 Code)
		}
		string ipPort;
		string name;
		bool op;
		bool disableDefaultSearch;
		//Sulan start svn101
		int imageIndex() {
			return 0;
		}
		//End
	};

	// WM_SPEAKER
	enum Speakers {
		ADD_RESULT,
		HUB_ADDED,
		HUB_CHANGED,
		HUB_REMOVED,
		// CDM EXTENSION BEGINS
		ADD_UNRESPONDED
		// CDM EXTENSION ENDS
	};

	string initialString;
	int64_t initialSize;
	SearchManager::SizeModes initialMode;
	SearchManager::TypeModes initialType;

	CStatusBarCtrl ctrlStatus;
	CEdit ctrlSearch;
	CComboBox ctrlSearchBox;
	CEdit ctrlSize;
	CComboBox ctrlMode;
	CComboBox ctrlSizeMode;
	CComboBoxEx ctrlFiletype;
	CImageList searchTypes;
	CButton ctrlDoSearch;
	// CDM EXTENSION BEGINS
	CButton ctrlShowUnresponded;
	CContainedWindow unrespondedContainer;
	CContainedWindow showUnrespondedContainer;
	TypedListViewCtrl<UnrespondedInfo, IDC_UNRESPONDED> ctrlUnresponded;
	CMenu unrespondedMenu;
	// CDM EXTENSION ENDS
	CContainedWindow searchContainer;
	CContainedWindow searchBoxContainer;
	CContainedWindow sizeContainer;
	CContainedWindow modeContainer;
	CContainedWindow sizeModeContainer;
	CContainedWindow fileTypeContainer;
	CContainedWindow fileTypeSubContainer;
	CContainedWindow slotsContainer;
	CContainedWindow showUIContainer;
	CContainedWindow doSearchContainer;
	CContainedWindow resultsContainer;
	CContainedWindow hubsContainer;
	// potheads extension starts (R2 Code) #7
	CContainedWindow tthContainer;
	CContainedWindow ctrlFilterContainer;
	CContainedWindow ctrlFilterSelContainer;
	string filter;
	//CStatic searchLabel, sizeLabel, optionLabel, typeLabel, hubsLabel;
	CStatic searchLabel, sizeLabel, optionLabel, typeLabel, hubsLabel, srLabel;
	//CButton ctrlSlots, ctrlShowUI;
	CButton ctrlSlots, ctrlShowUI, ctrlTTH;
	CImageList states;
	// potheads extension ends (R2 Code)
	
	bool showUI;

	TypedListViewCtrl<SearchInfo, IDC_RESULTS> ctrlResults;
	TypedListViewCtrl<HubInfo, IDC_HUB> ctrlHubs;

	CMenu resultsMenu;
	CMenu targetMenu;
	CMenu targetDirMenu;
	
	StringList search;
	StringList targets;
	StringList wholeTargets;
// R2 extension begins svn126
	CMenu copyMenu;
// R2 extension ends svn126

	// potheads extension starts (R2 Code) #7
	SearchInfo::List mainItems;
	CEdit ctrlFilter;
	CComboBox ctrlFilterSel;	
	// potheads extension ends (R2 Code)	

	/** Parameter map for user commands */
	StringMap ucParams;

	bool onlyFree;
	bool isHash;
	// potheads extension starts (R2 Code) #7
	bool exactSize;
	size_t droppedResults;
	// potheads extension ends (R2 Code)
	CriticalSection cs;

	static StringList lastSearches;

	DWORD lastSearch;
	bool closed;

	static int columnIndexes[];
	static int columnSizes[];

	void downloadSelected(const string& aDir, bool view = false); 
	void downloadWholeSelected(const string& aDir);
	void onEnter();
	void onTab(bool shift);

	void download(SearchResult* aSR, const string& aDir, bool view);
	
	// SearchManagerListener
	virtual void on(SearchManagerListener::SR, SearchResult* sr) throw() {
		onSearchResult(sr);
	}
	
	void onSearchResult(SearchResult* aResult);

	// ClientManagerListener
	virtual void on(ClientManagerListener::Types type, Client* client) throw() {
		switch(type) {
			case ClientManagerListener::CLIENT_CONNECTED:
				speak(HUB_ADDED, client); break;
			case ClientManagerListener::CLIENT_DISCONNECTED:
				speak(HUB_REMOVED, client); break;
			case ClientManagerListener::CLIENT_UPDATED:
				speak(HUB_CHANGED, client); break;
			default:
				break;
		}
	}

	void initHubs();
	void onHubAdded(HubInfo* info);
	void onHubChanged(HubInfo* info);
	void onHubRemoved(HubInfo* info);

	LRESULT onItemChangedHub(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);
	// CDM EXTENSION BEGINS
	LRESULT onRightClickHub(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);
	void removeUnresponded(const string& aNick);
	// CDM EXTENSION ENDS

	// potheads extension starts (R2 Code) #7

	void insertItem(int pos, SearchInfo* item);
	void updateSearchList();
	void Collapse(SearchInfo* i, int a);
	void Expand(SearchInfo* i, int a);
	// potheads extension ends (R2 Code)

	void speak(Speakers s, Client* aClient) {
		HubInfo* hubInfo = new HubInfo(aClient->getIpPort(), aClient->getName(), aClient->getOp(), aClient->getDisableSearchSelect());
		PostMessage(WM_SPEAKER, WPARAM(s), LPARAM(hubInfo)); 
	};
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_CHILDFRM_H__A7078724_FD85_4F39_8463_5A08A5F45E33__INCLUDED_)

/**
 * @file
 * $Id: SearchFrm.h 323 2005-08-25 18:01:34Z Pothead $
 */
